﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Tsanie.Image2Cmt {
    struct Color {
        public byte A;
        public byte R;
        public byte G;
        public byte B;

        public static bool operator ==(Color a, Color b) {
            return (a.A == b.A) &&
                   (a.R == b.R) &&
                   (a.G == b.G) &&
                   (a.B == b.B);
        }
        public static bool operator !=(Color a, Color b) {
            return !(a == b);
        }

        public override bool Equals(object obj) {
            if (obj is Color)
                return this == (Color)obj;
            return false;
        }
        public override int GetHashCode() {
            //return base.GetHashCode();
            return this.R << 16 | this.G << 8 | this.B;
        }
        public override string ToString() {
            return string.Format("[{0},{1},{2},{3}]", new object[] {
                this.A,
                this.R,
                this.G,
                this.B
            });
        }
    }

    struct HSL {
        /// <summary>
        /// Hue component.
        /// </summary>
        /// <remarks>Hue is measured in the range of [0, 359].</remarks>
        public int Hue;

        /// <summary>
        /// Saturation component.
        /// </summary>
        /// <remarks>Saturation is measured in the range of [0, 1].</remarks>
        public float Saturation;

        /// <summary>
        /// Luminance value.
        /// </summary>
        /// <remarks>Luminance is measured in the range of [0, 1].</remarks>
        public float Luminance;

        public static HSL FromRGB(Color rgb) {
            HSL hsl = new HSL();

            float r = (rgb.R / 255.0f);
            float g = (rgb.G / 255.0f);
            float b = (rgb.B / 255.0f);

            float min = Math.Min(Math.Min(r, g), b);
            float max = Math.Max(Math.Max(r, g), b);
            float delta = max - min;
            hsl.Luminance = (max + min) / 2;

            if (delta == 0) {
                // 灰度
                hsl.Hue = 0;
                hsl.Saturation = 0.0f;
            } else {
                // get saturation value
                hsl.Saturation = (hsl.Luminance <= 0.5) ? (delta / (max + min)) : (delta / (2 - max - min));
                // get hue value
                float hue;
                if (r == max) {
                    hue = ((g - b) / 6) / delta;
                } else if (g == max) {
                    hue = (1.0f / 3) + ((b - r) / 6) / delta;
                } else {
                    hue = (2.0f / 3) + ((r - g) / 6) / delta;
                }
                // correct hue if needed
                if (hue < 0)
                    hue += 1;
                if (hue > 1)
                    hue -= 1;
                hsl.Hue = (int)(hue * 360);
            }

            return hsl;
        }
    }

    static class ColorModel {
        public static readonly Color Empty = new Color() { A = 0, R = 0, G = 0, B = 0 };
        public static Color FromArgb(byte a, byte r, byte g, byte b) {
            return new Color() { A = a, R = r, G = g, B = b };
        }
        public static Color FromBgra(byte b, byte g, byte r, byte a) {
            return ColorModel.FromArgb(a, r, g, b);
        }
        public static Color FromRgb(byte r, byte g, byte b) {
            return ColorModel.FromArgb(255, r, g, b);
        }
        public static Color FromBgr(byte b, byte g, byte r) {
            return ColorModel.FromRgb(r, g, b);
        }
        public static Color FromColor(System.Drawing.Color color) {
            return new Color() { A = color.A, R = color.R, G = color.G, B = color.B };
        }

        public static int ToArgb(this Color c) {
            return c.A << 24 | c.R << 16 | c.G << 8 | c.B;
        }
        public static int ToRgb(this Color c) {
            return c.R << 16 | c.G << 8 | c.B;
        }
        public static string FormatColor(this Color c) {
            return c.ToArgb().ToString("X6");
        }
        public static Histogram<Color>[] ToColorHistogram(this System.Drawing.Color[] array) {
            if (array == null)
                return new Histogram<Color>[0];
            Histogram<Color>[] result = new Histogram<Color>[array.Length];
            for (int i = 0; i < array.Length; i++) {
                result[i].value = ColorModel.FromColor(array[i]);
                result[i].count = 0;
            }
            return result;
        }
    }
}
